package com.example.sendmessage.client;

import com.example.sendmessage.common.*;

import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Connection {
    // 客户端Socket
    private Socket socket = null;
    //  客户端Channel
    private ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();
    private InputStream inputStream;
    private OutputStream outputStream;
    private DataInputStream dataInputStream;
    private DataOutputStream dataOutputStream;
    private ExecutorService callbackPool = null;

    public Connection(String host, int port) throws IOException {
        // 客户端与服务器通过tcp进行连接
        this.socket = new Socket(host, port);
        // 获取输入输出流
        this.inputStream = socket.getInputStream();
        this.outputStream = socket.getOutputStream();
        this.dataInputStream = new DataInputStream(inputStream);
        this.dataOutputStream = new DataOutputStream(outputStream);
        // 创建线程池，用于处理接收到的消息
        this.callbackPool = Executors.newFixedThreadPool(4);
        // 启动接收消息的线程，不断从socket中读取响应
        Thread t = new Thread(() -> {
            try {
                while (!socket.isClosed()) {
                    // socket没有关闭就一直读取响应
                    Response response = readResponse();
                    dispatchResponse(response);
                }
            } catch (SocketException e) {
                // 此异常是正常断开异常
                System.out.println("[Connection] 连接正常断开！");
            } catch (IOException | MqException | ClassNotFoundException e) {
                System.out.println("[Connection] 连接异常断开！");
                e.printStackTrace();
            }
        });
        t.start();
    }

    private Response readResponse() throws IOException, MqException {
        Response response = new Response();
        response.setType(dataInputStream.readInt());
        response.setLength(dataInputStream.readInt());
        byte[] payload = new byte[response.getLength()];
        int n = dataInputStream.read(payload);
        if (n != response.getLength()) {
            throw new MqException("[Connection] 读取响应不完整");
        }
        response.setPayload(payload);
        System.out.println("[Connection] 接收到响应："+ response);
        return response;
    }

    private void dispatchResponse(Response response) throws IOException, ClassNotFoundException, MqException {
        // 判断是控制请求的响应，还是服务器推送的消息的响应
        if (response.getType() == 0xc) {
            // 这里的是服务器推送消息的响应
            SubscribeReturn subscribeReturn = (SubscribeReturn) BinaryTool.fromBytes(response.getPayload());
            String channelId = subscribeReturn.getChannelId();
            Channel channel = channelMap.get(channelId);
            if (channel == null) {
                throw new MqException("[Connection] 找不到对应的channel！channelId = " + channelId);
            }
            callbackPool.submit(() -> {
                // 执行客户端回调
                try {
                    channel.getConsumer().handleDelivery(subscribeReturn.getConsumerTag(), subscribeReturn.getBasicProperties(),
                            subscribeReturn.getBody());
                } catch (MqException | IOException e) {
                    System.out.println("[Connection] 执行客户端回调失败！");
                    e.printStackTrace();
                }
            });
        } else {
            // 控制请求的响应
            System.out.println();
        }
    }

    /**
     * 将客户端请求写入流中并发送个服务器
     * @param request 发送给服务器的请求
     */
    public void writeRequest(Request request) throws IOException {
        dataOutputStream.writeInt(request.getType());
        dataOutputStream.write(request.getLength());
        dataOutputStream.write(request.getPayload());
        dataOutputStream.flush();
        System.out.println("[Connection] 发送请求! type=" + request.getType() + ", length=" + request.getLength());
    }
}
